﻿#region using...
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
#endregion

namespace Infusion.Silverlight.Controls.Ribbon
{
    #region : ToolTip :
    public class ToolTip : Control
    {
        #region Dependency Properties...
        #region IDProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.ID dependency property.
        /// </summary>
        public static readonly DependencyProperty IDProperty = DependencyProperty.Register(
                "ID",
                typeof(string),
                typeof(ToolTip),
                null);
        #endregion

        #region TitleProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.Title dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
                "Title",
                typeof(string),
                typeof(ToolTip),
                null);
        #endregion

        #region DescriptionProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.Description dependency property.
        /// </summary>
        public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
                "Description",
                typeof(string),
                typeof(ToolTip),
                null);
        #endregion

        #region AlternativeDescriptionProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.AlternativeDescription dependency property.
        /// </summary>
        public static readonly DependencyProperty AlternativeDescriptionProperty = DependencyProperty.Register(
                "AlternativeDescription",
                typeof(string),
                typeof(ToolTip),
                null);
        #endregion

        #region ScreenTipSourceProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.ScreenTipSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ScreenTipSourceProperty = DependencyProperty.Register(
                "ScreenTipSource",
                typeof(string),
                typeof(ToolTip),
                null);
        #endregion

        #region ShowHelpProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.ToolTip.ShowHelp dependency property.
        /// </summary>
        public static readonly DependencyProperty ShowHelpProperty = DependencyProperty.Register(
                "ShowHelp",
                typeof(bool),
                typeof(ToolTip),
                null);
        #endregion
        #endregion

        #region Properties...
        #region ID
        public string ID
        {
            get { return (string)GetValue(IDProperty); }
            set { SetValue(IDProperty, value); }
        }
        #endregion

        #region Title
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        #endregion

        #region Description
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }
        #endregion

        #region AlternativeDescription
        public string AlternativeDescription
        {
            get { return (string)GetValue(AlternativeDescriptionProperty); }
            set { SetValue(AlternativeDescriptionProperty, value); }
        }
        #endregion

        #region ScreenTipSource
        public string ScreenTipSource
        {
            get { return (string)GetValue(ScreenTipSourceProperty); }
            set { SetValue(ScreenTipSourceProperty, value); }
        }
        #endregion

        #region ShowHelp
        public bool ShowHelp
        {
            get { return (bool)GetValue(ShowHelpProperty); }
            set { SetValue(ShowHelpProperty, value); }
        }
        #endregion
        #endregion
    }
    #endregion

    #region : RibbonToolTip :
    #region Template Parts...
    [TemplatePart(Name = RibbonToolTip.RibbonToolTipLayoutRoot, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonToolTip.CanvasDropShadow, Type = typeof(Canvas))]
    [TemplatePart(Name = RibbonToolTip.CanvasDropShadowClip, Type = typeof(RectangleGeometry))]
    [TemplatePart(Name = RibbonToolTip.CanvasToolTip, Type = typeof(Canvas))]
    [TemplatePart(Name = RibbonToolTip.CanvasToolTipClip, Type = typeof(RectangleGeometry))]
    [TemplatePart(Name = RibbonToolTip.GridMainLayout, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonToolTip.TxtTitle, Type = typeof(TextBlock))]
    [TemplatePart(Name = RibbonToolTip.GridScreenTipAndTextLayout, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonToolTip.ImgScreenTip, Type = typeof(Image))]
    [TemplatePart(Name = RibbonToolTip.TxtDescription, Type = typeof(TextBlock))]
    [TemplatePart(Name = RibbonToolTip.LineHelpBorder, Type = typeof(Line))]
    [TemplatePart(Name = RibbonToolTip.ImgHelp, Type = typeof(Image))]
    [TemplatePart(Name = RibbonToolTip.TxtHelp, Type = typeof(TextBlock))]
    [TemplatePart(Name = RibbonToolTip.RectBorder, Type = typeof(Rectangle))]
    [TemplatePart(Name = RibbonToolTip.AnimateOpacity, Type = typeof(Storyboard))]
    #endregion
    public class RibbonToolTip : Control
    {
        #region TemplatePart Names...
        public const string RibbonToolTipLayoutRoot = "RibbonToolTipLayoutRoot";
        public const string CanvasDropShadow = "CanvasDropShadow";
        public const string CanvasDropShadowClip = "CanvasDropShadowClip";
        public const string CanvasToolTip = "CanvasToolTip";
        public const string CanvasToolTipClip = "CanvasToolTipClip";
        public const string GridMainLayout = "GridMainLayout";
        public const string TxtTitle = "TxtTitle";
        public const string GridScreenTipAndTextLayout = "GridScreenTipAndTextLayout";
        public const string ImgScreenTip = "ImgScreenTip";
        public const string TxtDescription = "TxtDescription";
        public const string LineHelpBorder = "LineHelpBorder";
        public const string ImgHelp = "ImgHelp";
        public const string TxtHelp = "TxtHelp";
        public const string RectBorder = "RectBorder";
        public const string AnimateOpacity = "AnimateOpacity";
        #endregion

        #region TemplatePart Variables...
        internal Grid ribbonToolTipLayoutRoot;
        internal Canvas canvasDropShadow;
        internal RectangleGeometry canvasDropShadowClip;
        internal Canvas canvasToolTip;
        internal RectangleGeometry canvasToolTipClip;
        internal Grid gridMainLayout;
        internal TextBlock txtTitle;
        internal Grid gridScreenTipAndTextLayout;
        internal Image imgScreenTip;
        internal TextBlock txtDescription;
        internal Line lineHelpBorder;
        internal Image imgHelp;
        internal TextBlock txtHelp;
        internal Rectangle rectBorder;
        internal Storyboard animateOpacity;
        #endregion

        #region Class Variables...
        private bool templateApplied = false;
        private bool dirtyLayout = false;
        private DispatcherTimer timer;
        #endregion

        #region Dependency Properties...
        #region TitleProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonToolTip.Title dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
                "Title",
                typeof(string),
                typeof(RibbonToolTip),
                new PropertyMetadata(new PropertyChangedCallback(TitlePropertyChanged)));
        #endregion

        #region DescriptionProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonToolTip.Description dependency property.
        /// </summary>
        public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
                "Description",
                typeof(string),
                typeof(RibbonToolTip),
                new PropertyMetadata(new PropertyChangedCallback(DescriptionPropertyChanged)));
        #endregion

        #region AlternativeDescriptionProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonToolTip.AlternativeDescription dependency property.
        /// </summary>
        public static readonly DependencyProperty AlternativeDescriptionProperty = DependencyProperty.Register(
                "AlternativeDescription",
                typeof(string),
                typeof(RibbonToolTip),
                new PropertyMetadata(new PropertyChangedCallback(AlternativeDescriptionPropertyChanged)));
        #endregion

        #region ScreenTipSourceProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonToolTip.ScreenTipSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ScreenTipSourceProperty = DependencyProperty.Register(
                "ScreenTipSource",
                typeof(string),
                typeof(RibbonToolTip),
                new PropertyMetadata(new PropertyChangedCallback(ScreenTipSourcePropertyChanged)));
        #endregion

        #region ShowHelpProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonToolTip.ShowHelp dependency property.
        /// </summary>
        public static readonly DependencyProperty ShowHelpProperty = DependencyProperty.Register(
                "ShowHelp",
                typeof(bool),
                typeof(RibbonToolTip),
                new PropertyMetadata(new PropertyChangedCallback(ShowHelpPropertyChanged)));
        #endregion
        #endregion

        #region Dependency Property Changed Handlers...
        #region TitlePropertyChanged
        private static void TitlePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != null)
            {
                RibbonToolTip toolTip = (RibbonToolTip)obj;
                toolTip.dirtyLayout = true;

                toolTip.txtTitle.Text = args.NewValue.ToString();
            }
        }
        #endregion

        #region DescriptionPropertyChanged
        private static void DescriptionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion

        #region AlternativeDescriptionPropertyChanged
        private static void AlternativeDescriptionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion

        #region ScreenTipSourcePropertyChanged
        private static void ScreenTipSourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion

        #region ShowHelpPropertyChanged
        private static void ShowHelpPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != null)
            {
                RibbonToolTip toolTip = (RibbonToolTip)obj;
                toolTip.ShowHideHelp((bool)args.NewValue);
            }
        }
        #endregion
        #endregion

        #region Constructor(s)...
        #region RibbonToolTip
        public RibbonToolTip() : base()
        {
            DefaultStyleKey = typeof(RibbonToolTip);

            timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 20);
            timer.Tick += new EventHandler(timer_Tick);
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region ribbonToolTipLayoutRoot_LayoutUpdated
        private void ribbonToolTipLayoutRoot_LayoutUpdated(object sender, EventArgs e)
        {
            if (dirtyLayout)
            {
                double textHeight = (txtDescription.ActualHeight) + 15d;
                double height = textHeight + 24d + (ShowHelp ? 31d : 0d);

                canvasDropShadow.Height = height;
                canvasDropShadowClip.Rect = new Rect(0d, 0d, canvasDropShadowClip.Rect.Width, height);

                canvasToolTip.Height = height;
                canvasToolTipClip.Rect = new Rect(0d, 0d, canvasToolTipClip.Rect.Width, height);

                gridMainLayout.RowDefinitions[1].Height = new GridLength(textHeight);

                rectBorder.Height = height + 1d;

                dirtyLayout = false;
            }
        }
        #endregion

        #region animateOpacity_Completed
        private void animateOpacity_Completed(object sender, EventArgs e)
        {
            SetValue(Canvas.TopProperty, -5000d);
            SetValue(Canvas.LeftProperty, -5000d);
            ribbonToolTipLayoutRoot.Opacity = 1d;
        }
        #endregion

        #region timer_Tick
        private void timer_Tick(object sender, EventArgs e)
        {
            Hide();
        }
        #endregion
        #endregion

        #region Methods...
        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (!templateApplied)
            {
                ribbonToolTipLayoutRoot = (Grid)GetTemplateChild(RibbonToolTipLayoutRoot);
                canvasDropShadow = (Canvas)GetTemplateChild(CanvasDropShadow);
                canvasDropShadowClip = (RectangleGeometry)GetTemplateChild(CanvasDropShadowClip);
                canvasToolTip = (Canvas)GetTemplateChild(CanvasToolTip);
                canvasToolTipClip = (RectangleGeometry)GetTemplateChild(CanvasToolTipClip);
                gridMainLayout = (Grid)GetTemplateChild(GridMainLayout);
                txtTitle = (TextBlock)GetTemplateChild(TxtTitle);
                gridScreenTipAndTextLayout = (Grid)GetTemplateChild(GridScreenTipAndTextLayout);
                imgScreenTip = (Image)GetTemplateChild(ImgScreenTip);
                txtDescription = (TextBlock)GetTemplateChild(TxtDescription);
                lineHelpBorder = (Line)GetTemplateChild(LineHelpBorder);
                imgHelp = (Image)GetTemplateChild(ImgHelp);
                txtHelp = (TextBlock)GetTemplateChild(TxtHelp);
                rectBorder = (Rectangle)GetTemplateChild(RectBorder);
                animateOpacity = (Storyboard)GetTemplateChild(AnimateOpacity);

                ribbonToolTipLayoutRoot.LayoutUpdated += new EventHandler(ribbonToolTipLayoutRoot_LayoutUpdated);
                animateOpacity.Completed += new EventHandler(animateOpacity_Completed);

                if (!string.IsNullOrEmpty(Title))
                    txtTitle.Text = Title;

                if (!string.IsNullOrEmpty(Description))
                    SetDescription(false);
                else
                    if (!string.IsNullOrEmpty(AlternativeDescription))
                        SetDescription(true);

                if (!string.IsNullOrEmpty(ScreenTipSource))
                    imgScreenTip.Source = new BitmapImage(new Uri(ScreenTipSource, UriKind.Relative));

                ShowHideHelp(ShowHelp);

                templateApplied = true;
            }
        }
        #endregion

        #region SetDescription
        private void SetDescription(bool isAlternative)
        {
            string description = (isAlternative ? (string.IsNullOrEmpty(AlternativeDescription) ? Description : AlternativeDescription) : Description);
            dirtyLayout = true;

            int nextStart = 0;
            int indexOfBreak = description.IndexOf('|');

            if (indexOfBreak == -1)
            {
                txtDescription.Text = description;
            }
            else
            {
                txtDescription.Text = string.Empty;

                while (indexOfBreak != -1)
                {
                    if (nextStart != indexOfBreak)
                    {
                        Run run = new Run();
                        run.Text = description.Substring(nextStart, indexOfBreak);
                        txtDescription.Inlines.Add(run);
                    }
                    txtDescription.Inlines.Add(new LineBreak());

                    nextStart = indexOfBreak + 1;
                    indexOfBreak = description.IndexOf('|', nextStart);
                }

                Run lastRun = new Run();
                lastRun.Text = description.Substring(nextStart);
                txtDescription.Inlines.Add(lastRun);
            }
        }
        #endregion

        #region ShowHideHelp
        internal void ShowHideHelp(bool show)
        {
            gridMainLayout.RowDefinitions[2].Height = new GridLength(show ? 31 : 0);
            dirtyLayout = true;
        }
        #endregion

        #region Show
        internal void Show(double x, double y, bool isAlternativeDescription)
        {
            animateOpacity.Stop();

            if (ribbonToolTipLayoutRoot.Opacity < 1d)
                ribbonToolTipLayoutRoot.Opacity = 1d;

            SetDescription(isAlternativeDescription);

            SetValue(Canvas.LeftProperty, x);
            SetValue(Canvas.TopProperty, y);

            timer.Start();
        }
        #endregion

        #region Hide
        internal void Hide()
        {
            timer.Stop();
            animateOpacity.Begin();
        }
        #endregion
        #endregion

        #region Properties...
        #region Title
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        #endregion

        #region Description
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }
        #endregion

        #region AlternativeDescription
        public string AlternativeDescription
        {
            get { return (string)GetValue(AlternativeDescriptionProperty); }
            set { SetValue(AlternativeDescriptionProperty, value); }
        }
        #endregion

        #region ScreenTipSource
        public string ScreenTipSource
        {
            get { return (string)GetValue(ScreenTipSourceProperty); }
            set { SetValue(ScreenTipSourceProperty, value); }
        }
        #endregion

        #region ShowHelp
        public bool ShowHelp
        {
            get { return (bool)GetValue(ShowHelpProperty); }
            set { SetValue(ShowHelpProperty, value); }
        }
        #endregion
        #endregion
    }
    #endregion
}